#pragma once
#include <iostream>       // std::cout
#include <thread>         // std::thread

// lock_guard example
#include <mutex>          // std::mutex, std::lock_guard
#include <stdexcept>      // std::logic_error
#include <chrono>

namespace wkthread
{
 
    std::mutex mtx;
    void foo()
    {
        // do stuff...
        for  (int i = 0 ; i< 20;i++)
        {
            mtx.lock();
            std::cout << "foo" << std::endl;
            mtx.unlock();
            //Sleep(500);
            std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
    }
    void bar(int x)
    {
        // do stuff...
        while (x < 20)
        {
            mtx.lock();
            std::cout << "bar : " << x++ << std::endl;
            mtx.unlock();
            std::this_thread::sleep_for(std::chrono::milliseconds(6));
        }
    }
    void threadTest1()
    {
        std::thread first(foo);     // spawn new thread that calls foo()
        std::thread second(bar, 0);  // spawn new thread that calls bar(0)

        std::cout << "main, foo and bar now execute concurrently...\n";

        // synchronize threads:
        first.join();                // pauses until first finishes
        second.join();               // pauses until second finishes

        std::cout << "foo and bar completed.\n";
    }


    //std::mutex mtx;
    void print_even(int x) {
        if (x % 2 == 0) 
            std::cout << x << " is even\n";
        else 
            throw (std::logic_error("not even"));
    }

    void print_thread_id(int id) {
        try {
            // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
            std::lock_guard<std::mutex> lck(mtx);
            print_even(id);
        }
        catch (std::logic_error&) {
            std::cout << id << " : [exception caught]\n";
        }
    }

    void  threadTest2()
    {
        std::thread threads[10];
        // spawn 10 threads:
        for (int i = 0; i < 10; ++i)
            threads[i] = std::thread(print_thread_id, i + 1);

        for (auto& th : threads) th.join();
    }

    
}